package com.sigmatrix.h5.auth;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.sigmatrix.h5.components.RedisClient;
import com.sigmatrix.h5.entity.v2.DisPermission;
import com.sigmatrix.h5.entity.v2.DisRole;
import com.sigmatrix.h5.entity.v2.DisRolePermission;
import com.sigmatrix.h5.exception.MessageException;
import com.sigmatrix.h5.service.db.DisPermissionDBService;
import com.sigmatrix.h5.service.db.DisRoleDBService;
import com.sigmatrix.h5.service.db.DisRolePermissionDBService;
import com.sigmatrix.h5.utils.JacksonUtil;
import com.sigmatrix.h5.utils.MD5Utils;
import com.sigmatrix.h5.web.args.LoginParam;

/**
 * 默认身份认证.
 * 使用redis作为session存储介质
 * 
 * @author wei.wang
 *
 */
@Service("defaultAuthenticator")
public class DefaultAuthenticator implements IAuthenticate {
	private static Logger logger = LoggerFactory.getLogger(DefaultAuthenticator.class);
	/**
	 * token 失效时间
	 */
	public static final long EXPIRE_TIMEOUT = 30;
	/**
	 * token 失效单位:TimeUnit.DAYS
	 */
	public static final TimeUnit EXPIRE_TIME_UNIT = TimeUnit.DAYS;
	/**
	 * token 前缀
	 */
	public static final String SESSION_PREFIX = "login:";
	
	/**
	 * 图文验证码 前缀
	 */
	public static final String IMAGE_V_CODE_PREFIX = "imagevcode:";

	@Autowired
	protected RedisClient redisClient;

	@Autowired
	private DisPermissionDBService disPermissionService;

	@Autowired
	private DisRoleDBService disRoleService;

	@Autowired
	private DisRolePermissionDBService disRolePermissionService;

	@Override
	public boolean isLogin(String token) {
		return redisClient.hasKey(SESSION_PREFIX + token);
	}

	@Override
	public LoginSession getLoginSession(String token) {
		String login = redisClient.get(SESSION_PREFIX + token);
		if (login == null) {
			return null;
		}
		return JacksonUtil.readJson2Entity(login, LoginSession.class);
	}

	@Override
	public void expire(String token, long timeout) {
		redisClient.expire(SESSION_PREFIX + token, timeout, EXPIRE_TIME_UNIT);
	}

	@Override
	public AuthenticationInfo authenticate(LoginParam param) {
		throw new MessageException("未实现");
	}

	@Override
	public Collection<DisRole> getRoles(AuthenticationInfo authenticationInfo) {
		Integer principal = authenticationInfo.getPrincipal();
		/**
		 * 根据用户Id获取所有的角色
		 */
		return disRoleService.findByAcctId(principal.longValue());
	}

	@Override
	public Collection<DisPermission> getPermissions(Collection<DisRole> roles, AuthenticationInfo authenticationInfo) {
		if (roles == null) {
			return null;
		}
		List<Integer> roleIds = new ArrayList<>();
		for (DisRole disRole : roles) {
			roleIds.add(disRole.getId());
		}
		if(roleIds.isEmpty()){
			return null;
		}
		// 获取role-Permission关系
		List<DisRolePermission> rolePermissions = disRolePermissionService.findByRoleIds(roleIds);
		if (rolePermissions == null) {
			return null;
		}
		// 获取Permission
		List<DisPermission> permissions = new ArrayList<>();
		Map<Integer, DisPermission> allPermission = getAllPermissions();
		for (DisRolePermission disRolePermission : rolePermissions) {
			DisPermission disPermission = allPermission.get(disRolePermission.getPermissionId());
			if (disPermission != null) {
				permissions.add(disPermission);
			}
		}
		return permissions;
	}

	@Override
	public ILoginResponse login(LoginParam param) {
		AuthenticationInfo info = authenticate(param);
		if (info == null) {
			throw new MessageException("账号不存在");
		}
		Collection<DisRole> roles = getRoles(info);
		Collection<DisPermission> permissions = getPermissions(roles, info);
		if(permissions==null||permissions.isEmpty()){
			throw new MessageException("账号没有配置权限。");
		}
		
		//权限check
		if(param!=null){
			boolean isAllowed = false;
			for (DisPermission disPermission : permissions) {
				if(param.getLoginType()==null){					
					isAllowed = true;
					break;
				}
				if(param.getLoginType().contains(disPermission.getCode())){
					isAllowed = true;
					break;
				}
			}
			if(!isAllowed){
				throw new MessageException("您没有访问该模块的权限");
			}
		}
		
		LoginSession session = new LoginSession();
		session.setInfo(info);
		session.setRoles(roles);
		session.setPermissions(permissions);
		String token = generateToken(info);
		session.setToken(token);
		String sessionStr = JacksonUtil.write2JsonString(session);
		logger.info("Login-session信息：{}",sessionStr);
		ILoginResponse response = convert(session);
		redisClient.set(SESSION_PREFIX + token, sessionStr, EXPIRE_TIMEOUT, EXPIRE_TIME_UNIT);
		return response;
	}

	@Override
	public String generateToken(AuthenticationInfo authenticationInfo) {
		return MD5Utils.getMD5Code(System.currentTimeMillis() + authenticationInfo.getLoginName());
	}

	/**
	 * LoginSession--转换-->ILoginResponse
	 * 
	 * @param session
	 * @return
	 */
	public ILoginResponse convert(LoginSession session) {
		throw new MessageException("未实现");
	}

	@Override
	public void logout(String token) {
		redisClient.delete(SESSION_PREFIX + token);
	}

	private Map<Integer, DisPermission> getAllPermissions() {
		if (this.cachPermissions == null||cachPermissions.isEmpty()) {
			DisPermission entity = new DisPermission();
			List<DisPermission> permissions = disPermissionService.selectList(new EntityWrapper<DisPermission>(entity));
			Map<Integer, DisPermission> collect = permissions.stream()
					.collect(Collectors.toMap(DisPermission::getId, disPermission -> disPermission));
			this.cachPermissions = collect;
		}

		if (this.cachPermissions == null || cachPermissions.isEmpty()) {
			throw new MessageException("db中权限数据，加载失败。");
		}
		return this.cachPermissions;
	}

	/**
	 * 缓存数据库中所有的权限数据
	 */
	private Map<Integer, DisPermission> cachPermissions = null;

}
